#pragma once
#include "config.hpp"
#include <chrono>
#include <cstdint>
#include <string>
#include <functional>

#include <PID.hpp>
#include <IMU.hpp>
#include <joystick.hpp>
#include <motor_RS485.hpp>
#include <motor_CAN.hpp>

#include <netServer.hpp>
#include <recorder.hpp>

class Application
{
  public:
    struct Devices
    {
        IMU imu;
        bool useCan;
        Motor_RS485 motorLeft;
        Motor_RS485 motorRight;
        Motor_Can motorCanLeft;
        Motor_Can motorCanRight;
        JoyStick stick;
    };

    struct RunningState
    {
        bool hasStick;
        float fps;
        float deltaTimeMs;
        int64_t loopCount;
    };
    struct Input
    {
        float move;
        float rotate;
    };

    bool LoadConfig(std::string configPath);
    virtual bool Init();
    bool Loop();
    virtual void Quit(){};
    void SimpleStart(std::string configPath);

  protected:
    Config config;
    Devices device;
    RunningState state;
    // rewrite this for custorm loop
    virtual bool OnTick(Input input) { return false; }
    //-1 for ignore interval control,unit is ms
    void SetTickInterval(float ms);
    /*helpful functions*/
    void FrequencyDividerInvoke(int divid, int &count, const std::function<void()> &func);
    using Message = std::vector<std::pair<std::string, float>>;
    void PrintOut(Message message);
    void RecordAll(Recorder &recorder, Message message);
    void ServerUpload(NetServer &server, Message message);
    bool CheckValueRange(float value, float rangeMin, float rangeMax, std::string tag);
    void CheckValueRangeAndExit(float value, float rangeMin, float rangeMax, std::string tag);

  private:
    // bool enableRecord = false;
    std::chrono::steady_clock::time_point lastTick;
    std::chrono::steady_clock::duration tickInterval{-1};
};